package org.nvm.core;

import org.nvm.dic.Dictionary;

/**
 * 分词结果链
 * @author ThinkPad
 *
 */
public class LexemePath extends QuickSortSet implements Comparable<LexemePath> {
	
	private int pathBegin;
	private int pathEnd;
	private int payloadLength;
	
	private char[] srcContent;
	private int absBegin;
	private int absLength;
	
	private static final float NULL_RESULT = -1f;
	private float _result = NULL_RESULT;
	
	private void initPath() {
		this.pathBegin = -1;
		this.pathEnd = -1;
		this.payloadLength = 0;
	}
	public LexemePath() {
		initPath();
	}
	public LexemePath(char[] content, int absBegin, int textLength) {
		initPath();
		this.srcContent = content;
		this.absBegin = absBegin;
		this.absLength = textLength;
	}
	
	boolean addCrossLexeme(Lexeme lexeme) {
		if(this.isEmpty()) {
			this.addLexeme(lexeme);
			
			this.pathBegin = lexeme.getBegin();
			this.pathEnd = lexeme.getBegin() + lexeme.getLength();
			this.payloadLength = lexeme.getLength();
			return true;
			
		} else if(checkCross(lexeme)) {
			this.addLexeme(lexeme);
			int newEnd = lexeme.getBegin() + lexeme.getLength();
			if(newEnd > this.pathEnd) {
				this.pathEnd = newEnd;
			}
			this.payloadLength = this.pathEnd - this.pathBegin;
			return true;
		}
		
		return false;
	}
	
	boolean addNotCrossLexeme(Lexeme lexeme) {
		if(this.isEmpty()) {
			this.addLexeme(lexeme);
			
			this.pathBegin = lexeme.getBegin();
			this.pathEnd = lexeme.getBegin() + lexeme.getLength();
			this.payloadLength = lexeme.getLength();
			return true;
		} else if(!checkCross(lexeme)) {
			this.addLexeme(lexeme);
			
			Lexeme head = getHead();
			this.pathBegin = head.getBegin();
			Lexeme tail = getTail();
			this.pathEnd = tail.getBegin() + tail.getLength();
			
			this.payloadLength += lexeme.getLength();
			return true;
		}
		return false;
	}
	
	Lexeme removeTail() {
		Lexeme tail = shiftTail();
		if(isEmpty()) {
			initPath();
		} else {
			this.payloadLength += tail.getLength();
			Lexeme currentTail = getTail();
			this.pathEnd = currentTail.getBegin() + currentTail.getLength();
		}
		
		return tail;
	}
	
	/**
	 * 检查分词是否相交
	 * @param lexeme
	 * @return
	 */
	public boolean checkCross(Lexeme lexeme) {
		return this.pathBegin <= lexeme.getBegin() && this.pathEnd > lexeme.getBegin() ||
				lexeme.getBegin() <= this.pathBegin && lexeme.getBegin() + lexeme.getLength() > this.pathEnd;
	}

	public int getPathBegin() {
		return pathBegin;
	}
	public int getPathEnd() {
		return pathEnd;
	}
	public int getPayloadLength() {
		return payloadLength;
	}
	public int getPathLength() {
		return this.pathEnd - this.pathBegin;
	}
	
	int getXWeight() {
		int weight = 1;
		Cell cell = getHeadCell();
		while(cell != null && cell.getLexeme() != null) {
			weight *= cell.getLexeme().getLength();
			cell = cell.getNext();
		}
		return weight;
	}
	int getVWeight() {
		int weight = 1;
		int index = 1;
		Cell cell = getHeadCell();
		while(cell != null && cell.getLexeme() != null) {
			weight += index ++ * cell.getLexeme().getLength();
			cell = cell.getNext();
		}
		return weight;
	}
	
	LexemePath copy() {
		LexemePath copy = new LexemePath(this.srcContent, this.absBegin, this.absLength);
		copy.pathBegin = this.pathBegin;
		copy.pathEnd = this.pathEnd;
		copy.payloadLength = this.payloadLength;
		
		//copy cell.lexeme
		Cell pointer = this.getHeadCell();
		while(pointer != null && pointer.getLexeme() != null) {
			copy.addLexeme(pointer.getLexeme());
			pointer = pointer.getNext();
		}
		
		return copy;
	}
	

	@Override
	public int compareTo(LexemePath o) {
		float currentResult = caculateResult(),
				oResult = o.caculateResult();
		if(currentResult > oResult) {
			return 1;
		} else if(currentResult < oResult) {
			return -1;
		} else {
			if(this.pathEnd > o.pathEnd) {
				return 1;
			} else if(this.pathEnd < o.pathEnd) {
				return -1;
			}
		}
		return 0;
	}
	
	private float caculateResult() {
		if(_result == NULL_RESULT) {
			_result = this.payloadLength + (-1) * this.size() + this.getPathLength() + this.getXWeight() + this.getVWeight();
			
			if(this.payloadLength < this.absLength) {
				float sumFreq = 0;
				int cursor = this.absBegin;
				Cell head = this.getHeadCell();
				
				char singleChar;
				while(head != null && head.getLexeme() != null) {
					while(cursor < head.getLexeme().getBegin()) {
						singleChar = srcContent[cursor];
						
						float freq = Dictionary.getInstance().getCharFrequency(singleChar);
						
						sumFreq += freq;
						cursor ++;
					}
					
					cursor += head.getLexeme().getLength();
					head = head.getNext();
				}
				
				while(cursor < this.absBegin + this.absLength) {
					singleChar = srcContent[cursor];
					
					float freq = Dictionary.getInstance().getCharFrequency(singleChar);
					
					sumFreq += freq;
					
					cursor ++;
				}
				
				_result += sumFreq * 2;
			}
		}
		return _result;
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		sb.append("\n\r");
		sb.append("pathBegin  : ").append(pathBegin).append("\r\n");
		sb.append("pathEnd  : ").append(pathEnd).append("\r\n");
		sb.append("payloadLength  : ").append(payloadLength).append("\r\n");
		Cell head = this.getHeadCell();
		while(head != null){
			sb.append("lexeme : ").append(head.getLexeme()).append("\r\n");
			head = head.getNext();
		}
		return sb.toString();
	}
}
